package com.quwan.app.controller;


import com.quwan.anno.AccessCount;
import com.quwan.app.service.MemberService;
import com.quwan.app.vo.*;
import com.quwan.app.vo.account.BindAccParams;
import com.quwan.app.vo.pay.TransInfoDTO;
import com.quwan.app.vo.pay.TransferParams;
import com.quwan.app.vo.pay.TransferResult;
import com.quwan.common.BaseController;
import com.quwan.common.Check;
import com.quwan.common.enums.AuthFaceEnum;
import com.quwan.common.enums.BindAccEnum;
import com.quwan.common.enums.TransEnum;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.form.IdForm;
import com.quwan.common.result.ApiResult;
import com.quwan.common.result.PageResult;
import com.quwan.common.result.ResultCode;
import com.quwan.component.ComponentFactory;
import com.quwan.constans.AppConst;
import com.quwan.constans.CacheKey;
import com.quwan.entity.TMember;
import com.quwan.entity.TMemberAlbum;
import com.quwan.utils.Parse;
import com.quwan.utils.redis.Redis;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author quan
 * @date 2021-06-22 14:20
 */
@Api(tags = "App会员")
@RestController
@Validated
@RequestMapping("app/member")
@RequiredArgsConstructor
public class MemberController extends BaseController {
    private final MemberService memberService;
    private final ComponentFactory componentFactory;
    @Autowired
    @Qualifier("asyncThread")
    private ThreadPoolTaskExecutor executor;
    private final Redis redis;

    @AccessCount
    @ApiOperation("钱包")
    @PostMapping("/purse")
    public ApiResult<BalanceInfoDTO> memberPurse(HttpServletRequest request) {
        BalanceInfoDTO res = new BalanceInfoDTO();
        BeanUtils.copyProperties(memberService.getMemberMoneyInfo(Long.parseLong(getId(request))), res);
        return ApiResult.success(res);
    }

    @AccessCount
    @ApiOperation("查看会员基本信息/单向获取 或 双向获取均可")
    @GetMapping("/baseInfo")
    public ApiResult<MemberInfoDTO> memberInfo(HttpServletRequest request,
                                               @ApiParam("当前登录用户id(非必须) 游客登录无token 需id") @RequestParam(required = false) String currentMember,
                                               @ApiParam("查询目标会员信息(必须)") @RequestParam final String targetMember) {

        try {
            currentMember = getId(request);
        } catch (Exception e) {
        }
        String currentMid = currentMember;
        MemberInfoDTO dto = new MemberInfoDTO();
        CompletableFuture<Map<String, Long>> follow = CompletableFuture.supplyAsync(() -> {
            if (StringUtils.isNotBlank(currentMid) && !targetMember.equalsIgnoreCase(currentMid)) {
                memberService.saveMemberVisit(currentMid, targetMember); //访客记录
                return memberService.followAndBlackList(currentMid, targetMember); //黑名单
            }
            return null;
        }, executor);

        TMember member = memberService.getMemberInfoById(targetMember);
        Check.notNull(member, ExpCode.MEMBER_NOT_EXIST);
        MemberDashboardData dashboardData = memberService.getDashboardData(Long.parseLong(targetMember.trim())); //社交数据
        dto.setAlbums(memberService.getMemberAlbumsByMId(targetMember).stream().map(TMemberAlbum::getUrl).collect(Collectors.toList()));
        BeanUtils.copyProperties(dashboardData, dto);
        BeanUtils.copyProperties(member, dto);//基础信息
        try {
            Map<String, Long> map = follow.get();
            dto.setFollow(map != null && map.get("follow") > 0);
            dto.setBlackList(map != null && map.get("black") > 0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String yearStr = "";
        Integer age = dto.getAge();
        if (age != null && age != 0) {
            int year = LocalDate.now().getYear() - age;
            yearStr = String.valueOf(year).toCharArray()[2] + "0后";

        }
        dto.setIdentity(member.getIdStatus() > 0)
                .setMobile("****")
                .setBalance(BigDecimal.ZERO)
                .setFaceBool(AuthFaceEnum.FINISH.getCode().equals(member.getFaceStatus()))
                .setZfbAuth(StringUtils.isNotBlank(member.getZfbOpenId()))
                .setWxAuth(StringUtils.isNotBlank(member.getWxOpenId()))
                .setYear(yearStr);
       // if (dto.isVip())
            dto.setHomeBackground(memberService.getHomeBackground(dto.getId()));
        return ApiResult.success(dto);

    }

    @ApiOperation("vip背景图需改")
    @PostMapping("/bg")
    public ApiResult updHomeBackGround(HttpServletRequest request,
                                       @ApiParam(value = "背景url") @RequestParam String url) {
        String id = getId(request);

        memberService.addBackGround(id, url);
        return ApiResult.success();

    }

    @ApiOperation("关注/取消 （会员）")
    @PostMapping("/follow")
    public ApiResult followMember(HttpServletRequest request,
                                  @ApiParam(value = "关注对象mId") @RequestParam String obj,
                                  @ApiParam(value = "0:取消关注 1:关注") @RequestParam String type) {
        String current = getId(request);
        if (current.equals(obj))
            return ApiResult.error(ExpCode.NOT_FOLLOW_SELF);
        boolean success = memberService.followMember(current, obj, type);
        if (success) return ApiResult.success();
        else return ApiResult.error(ResultCode.INTERNAL_SERVER_ERROR);

    }

    @ApiOperation("绑定open Id")
    @PostMapping("/bdzfb")
    public ApiResult bindZFBId(HttpServletRequest request,
                               @ApiParam("调用授权页面拿到的code") @RequestParam String code,
                               @ApiParam("type：1-wx 2-zfb") @RequestParam(defaultValue = "2") String type) {

        Predicate<BindAccParams> instance = componentFactory.getBindAccInstance(BindAccEnum.getByType(type));
        boolean success = instance.test(new BindAccParams(getId(request), code));
        if (success)
            return ApiResult.success();
        return ApiResult.error(ExpCode.OPEN_ID_BIND_FAIL);
    }


    @ApiOperation("会员余额提现信息")
    @PostMapping("/trans/info")
    public ApiResult<TransInfoDTO> transInfo(HttpServletRequest request,
                                             @ApiParam("提现金额") @RequestParam final String amount) {
        double money = Double.parseDouble(amount);
        Check.state(money <= 5000 && money >= 20, ExpCode.TRANS_MONEY_LIMIT);
        TransInfoDTO res = memberService.computeTransInfo(getId(request), amount);
        return ApiResult.success(res);

    }

    @ApiOperation("会员余额提现")
    @PostMapping("/trans")
    public ApiResult trans(HttpServletRequest request,
                           @ApiParam("操作金额") @RequestParam final String amount,
                           @ApiParam("支付密码") @RequestParam(defaultValue = "-1") final String payKey,
                           @ApiParam("提现方式 1-wx 2-zfb") @RequestParam final String type) {
        if ("1".equals(type))
            return ApiResult.error("微信提现暂不支持,请选择其他提现方式");
        double money = Double.parseDouble(amount);
        Check.state(money <= 5000 && money >= 20, ExpCode.TRANS_MONEY_LIMIT);
        //检查提现次数
        String mId = getId(request);
        String time = LocalDate.now().toString();
        Object o = redis.hGet(CacheKey.USER.transCount + mId, time);
        Integer count = Parse.toInt(o, 0);
        if (count == 3)
            return ApiResult.error("当天提现次数已用完,每天可以提现3次");

        Function<TransferParams, TransferResult> transInstance = componentFactory.getTransInstance(TransEnum.getByType(type));
        memberService.memberTrans(mId, amount, type, payKey, transInstance);
        redis.hSet(CacheKey.USER.transCount + mId, time, count + 1);
        return ApiResult.success();

    }

    @ApiOperation("会员建议")
    @PostMapping("/ask")
    public ApiResult ask(HttpServletRequest request,
                         @ApiParam("内容") @RequestParam String content,
                         @ApiParam("图片") @RequestParam(required = false) String img) {
        boolean success = memberService.addMemberAsk(getId(request), content, img);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("会员举报")
    @PostMapping("/report")
    public ApiResult report(HttpServletRequest request,
                            @ApiParam("被举报用户id") @RequestParam String targetMId,
                            @ApiParam("内容") @RequestParam String content,
                            @ApiParam("原因") @RequestParam String reason,
                            @ApiParam("图片") @RequestParam(required = false) String img) {
        String currentMId = getId(request);
        if (currentMId.equals(targetMId))
            return ApiResult.error(ExpCode.OPERATE_ERR);
        boolean success = memberService.addMemberReport(currentMId, reason, targetMId, content, img);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);

    }

    @ApiOperation("编辑会员信息")
    @PostMapping("/editProfile")
    public ApiResult report(HttpServletRequest request,
                            @ApiParam("头像") @RequestParam(required = false) String imgUrl,
                            @ApiParam("昵称") @RequestParam(required = false) String nickName,
                            @ApiParam("身高") @RequestParam(required = false) Integer height,
                            @ApiParam("生日") @RequestParam(required = false) String birthday,
                            @ApiParam("地区") @RequestParam(required = false) String area,
                            @ApiParam("职业") @RequestParam(required = false) String job,
                            @ApiParam("签名") @RequestParam(required = false) String sign,
                            @ApiParam("年龄") @RequestParam(required = false) Integer age,
                            @ApiParam("性别 0-女 1-男") @RequestParam(required = false) Integer gender) {
        boolean success = memberService.editMemberInfo(Long.parseLong(getId(request)), imgUrl, nickName, height, birthday, area, job, sign, age, gender);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("添加/修改 会员相册信息")
    @PostMapping("/updAlbums")
    public ApiResult updAlbums(HttpServletRequest request,
                               @ApiParam("相册 多个,间隔 排序 按,间隔顺序") @RequestParam String imgUrl) {
        boolean success = memberService.updAlbums(Long.parseLong(getId(request)), imgUrl);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }


    @AccessCount
    @ApiOperation("(2.5)身份证认证")
    @PostMapping("v2.5/identityChecked")
    public ApiResult identityChecked(HttpServletRequest request,
                                     @ApiParam("真实名称") @RequestParam String name,
                                     @ApiParam("身份证号") @RequestParam String idCode,
                                     @ApiParam("生活照 3张 数组或字符串 ,分割") @RequestParam(required = false) String lifeUrl,
                                     @ApiParam("身份证图片 2张 数组或字符串 ,分割") @RequestParam String urls) {
        String mId = getId(request);
        if (StringUtils.isBlank(urls) || urls.split(",").length < 2)
            return ApiResult.error("图片参数缺失");

//        if (StringUtils.isBlank(lifeUrl) || lifeUrl.split(",").length < 3)
//            return ApiResult.error("图片参数缺失");

        if (idCode.length() != 18) {
            return ApiResult.error("身份证长度不匹配");
        }
        if (StringUtils.isBlank(name) || name.length() > 5)
            return ApiResult.error("姓名不匹配");
        //判断出生时间
        String timeBir = idCode.substring(6, 14);
        String year = timeBir.substring(0, 4);
        String month = timeBir.substring(4, 6);
        String dayOfMonth = timeBir.substring(6);
        Integer sex = Integer.valueOf(idCode.substring(16, 17));

        boolean success = memberService.identityCheckedNew(mId, name, sex % 2, year + "/" + month + "/" + dayOfMonth, lifeUrl, idCode, urls);
        return success ? ApiResult.success() : ApiResult.error(ExpCode.AUTH_CODE_FAIL);

    }

    @Deprecated
    @ApiOperation("会员身份证认证")
    @PostMapping("/identityChecked")
    public ApiResult identityChecked(HttpServletRequest request,
                                     @ApiParam("真实名称") @RequestParam String name,
                                     @ApiParam("性别(0女 1男)") @RequestParam Integer gender,
                                     @ApiParam("出生时间(格式 2010/01/01)") @RequestParam String birthday,
                                     @ApiParam("地址") @RequestParam String area,
                                     @ApiParam("身份证号") @RequestParam String idCode,
                                     @ApiParam("身份证图片 2张 数组或字符串 ,分割") @RequestParam String urls) {
        String mId = getId(request);
        if (StringUtils.isBlank(urls) || urls.split(",").length < 2)
            return ApiResult.error("图片参数缺失");
        if (idCode.length() != 18) {
            return ApiResult.error("身份证长度不匹配");
        }
        if (StringUtils.isBlank(name) || name.length() > 4)
            return ApiResult.error("姓名不匹配");
        //判断出生时间
        String timeBir = idCode.substring(6, 14);
        String birth = birthday.replace("/", "");
        if (!birth.equals(timeBir)) {
            return ApiResult.error("身份证错误");
        }
        //身份证17位 奇数为男 偶数为女
        Integer sex = Integer.valueOf(idCode.substring(16, 17));
        if (gender.equals(0)) {
            if (sex % 2 != 0) {
                return ApiResult.error("身份证认证失败");
            }
        } else {
            if (sex % 2 == 0) {
                return ApiResult.error("身份证认证失败");
            }
        }
        boolean result = memberService.identityChecked(mId, name, gender, birthday, area, idCode, urls);
        if (result) {
            return ApiResult.success();
        } else {
            return ApiResult.error(ExpCode.OPEN_ID_BIND_FAIL);
        }
    }

    @ApiOperation("设置登录密码")
    @PostMapping("/spwd")
    public ApiResult savePassword(HttpServletRequest request,
                                  @Pattern(regexp = AppConst.REG_NOT_SPACE, message = "请正确输入密码")
                                  @ApiParam("登录密码") @RequestParam("pwd") String password,
                                  @ApiParam("手机验证码 首次设置不用传参") @RequestParam(value = "vc", required = false) String vcode) {

        if (StringUtils.isBlank(vcode)) {
            if (memberService.saveMemberPassword(getId(request), password))
                return ApiResult.success();
        } else {
            //todo 手机验证码重置登录密码
        }
        return ApiResult.error(ExpCode.OPERATE_FAIL);
    }

    @ApiOperation("修改登录密码")
    @PostMapping("/upwd")
    public ApiResult updPassword(HttpServletRequest request,
                                 @Pattern(regexp = AppConst.REG_NOT_SPACE, message = "请正确输入密码") @ApiParam("旧密码") @RequestParam("opwd") String oldPassword,
                                 @Pattern(regexp = AppConst.REG_NOT_SPACE, message = "请正确输入密码") @ApiParam("新密码") @RequestParam("npwd") String newPassword) {

        if (oldPassword.equals(newPassword))
            return ApiResult.error(ExpCode.PASSWORD_SAME);

        if (memberService.updMemberPassword(getId(request), oldPassword, newPassword))
            return ApiResult.success();
        return ApiResult.error(ExpCode.OPERATE_FAIL);
    }

    @ApiOperation("设置支付密码")
    @PostMapping("/setppwd")
    public ApiResult savePayPassword(HttpServletRequest request,
                                     @ApiParam("支付密码") @RequestParam("ppwd") String payPassword,
                                     @ApiParam("手机验证码 首次设置不用传参") @RequestParam(value = "vc", required = false) String vcode) {
        if (StringUtils.isNotBlank(vcode)) {
            // todo 验证码重置方式
        } else if (memberService.savePayPwd(getId(request), payPassword))
            return ApiResult.success();

        return ApiResult.error(ExpCode.OPERATE_FAIL);
    }

    @ApiOperation("修改支付密码")
    @PostMapping("/cppwd")
    public ApiResult updPayPassword(HttpServletRequest request,
                                    @ApiParam("旧支付密码") @RequestParam("oppwd") String oldPayPassword,
                                    @ApiParam("新支付密码") @RequestParam("nppwd") String newPayPassword) {

        if (memberService.updPayPwd(getId(request), oldPayPassword, newPayPassword))
            return ApiResult.success();

        return ApiResult.error(ExpCode.OPERATE_FAIL);
    }

    @ApiOperation("添加/移除黑名单")
    @PostMapping("/operateBL")
    public ApiResult operateBlackList(HttpServletRequest request,
                                      @ApiParam("拉黑会员id") @RequestParam("id") Long obj,
                                      @ApiParam("0移除 1添加") @RequestParam() Integer status) {
        String currentId = getId(request);
        if (currentId.equals(String.valueOf(obj)))
            return ApiResult.error(ExpCode.OPERATE_ERR);
        memberService.operateBlackList(currentId, obj, status);
        return ApiResult.success();
    }

    @ApiOperation("黑名单列表")
    @PostMapping("/bl")
    public ApiResult<PageResult<BlackListDTO>> blackList(HttpServletRequest request,
                                                         @RequestParam(defaultValue = "1") int pageNo,
                                                         @RequestParam(defaultValue = "10") int pageSize) {
        return ApiResult.success(memberService.blackList(getId(request), pageNo, pageSize));
    }

    @ApiOperation("隐私(开关)")
    @PostMapping("/seeForStatus")
    public ApiResult changeSeeForStatus(HttpServletRequest request,
                                        @ApiParam("1查看我发布的订单 2查看我的动态 3 查看我的粉丝") @RequestParam String type,
                                        @ApiParam("0关闭 1正常") @RequestParam Integer status) {
        boolean success = memberService.changeSeeForStatus(getId(request), type, status);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("（收藏/取消收藏）订单")
    @GetMapping("/collect/order")
    public ApiResult collectPublishOrder(HttpServletRequest request,
                                         @ApiParam("订单id") @RequestParam("id") String publishId,
                                         @ApiParam("0取消 1收藏") @RequestParam Integer status) {
        boolean success = memberService.collectPublishOrder(getId(request), publishId, status);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("我的粉丝详情")
    @GetMapping("/me/follower")
    public ApiResult<PageResult<MeFollowersDTO>> myFollowersDetail(HttpServletRequest request, int pageNo, int pageSize) {
        return ApiResult.success(memberService.getMyFollowersDetail(getId(request), pageNo, pageSize));
    }

    @ApiOperation("我的关注详情情")
    @GetMapping("/me/follow")
    public ApiResult<PageResult<MeFollowersDTO>> myFollowDetail(HttpServletRequest request, int pageNo, int pageSize) {
        return ApiResult.success(memberService.getMyFollowDetail(getId(request), pageNo, pageSize));
    }

    @ApiOperation("我的收藏（收藏发单列表）")
    @GetMapping("/me/collect/list")
    public ApiResult<PageResult<FollowOrderDTO>> myCollectOrder(HttpServletRequest request, int pageNo, int pageSize) {
        return ApiResult.success(memberService.getMyCollectOrderList(getId(request), pageNo, pageSize));
    }

    @ApiOperation("我的收藏（赞过）")
    @GetMapping("/me/zan/list")
    public ApiResult<PageResult<MemberDynamicDTO>> myZanDynamic(HttpServletRequest request, int pageNo, int pageSize) {
        return ApiResult.success(memberService.getMyZanDynamicList(getId(request), pageNo, pageSize));
    }

    @ApiOperation("消息通知(开关)")
    @PostMapping("/msg/notice")
    public ApiResult changeMsgNoticeStatus(HttpServletRequest request,
                                           @ApiParam("1订单消息 2聊天消息 3动态消息") @RequestParam String type,
                                           @ApiParam("0关闭 1正常") @RequestParam Integer status) {
        boolean success = memberService.changeMsgNoticeStatus(getId(request), type, status);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }


    @ApiOperation("用户注销")
    @PostMapping("/logOut")
    @ResponseBody
    public ApiResult updateMemberStatus(HttpServletRequest request ,String id) {
        String mid = getId(request);
        boolean success = memberService.updateMember(mid,id);
        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("绑定手机号")
    @PostMapping("/bindPhone")
    public ApiResult bindPhone(HttpServletRequest request,
                               @ApiParam("手机") @RequestParam String mobile,
                               @ApiParam("验证码") @RequestParam String code) {
        boolean success = memberService.bindPhone(getId(request), mobile, code);

        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("人脸认证")
    @PostMapping("/face")
    public ApiResult authFace(HttpServletRequest request,
                              @ApiParam("人脸连接") @RequestParam String url) {
        boolean success = memberService.authFace(getId(request), url);

        if (success)
            return ApiResult.success();

        return ApiResult.error(ResultCode.FAIL);
    }

    @ApiOperation("我的足迹（访问过的订单历史记录）")
    @GetMapping("/me/history/list")
    public ApiResult<PageResult<FollowOrderDTO>> myAccessHistoryOrderList(HttpServletRequest request, int pageNo, int pageSize) {
        return ApiResult.success(memberService.getMyAccessHistoryOrderList(getId(request), pageNo, pageSize));
    }

    @ApiOperation("我的评价（订单评价列表）")
    @GetMapping("/me/comment/list")
    public ApiResult<PageResult<ConsumeOrderCommentDTO>> myCommentOrderList(HttpServletRequest request, int pageNo, int pageSize,
                                                                            @RequestParam @ApiParam("0-未评价  1已评价") String type) {
        return ApiResult.success(memberService.getMyCommentOrderList(getId(request), pageNo, pageSize, type));
    }

    @ApiOperation("访客列表（谁看过我）")
    @GetMapping("/me/visit/list")
    public ApiResult<PageResult<MemberShowInfo>> visitList(HttpServletRequest request, @RequestParam(defaultValue = "1") int pageNo, @RequestParam(defaultValue = "10") int pageSize) {
        return ApiResult.success(memberService.getVisitList(getId(request), pageNo, pageSize));
    }

    @ApiOperation("获取系统im会话列表")
    @GetMapping("/pull/session")
    public ApiResult pullSession(HttpServletRequest request) {
        memberService.pullSystemSession(getId(request));
        return ApiResult.success();
    }

    @AccessCount
    @ApiOperation("推广信息）")
    @GetMapping("/me/spread/data")
    public ApiResult<MemberSpreadDataDTO> memberSpreadData(HttpServletRequest request) {
        MemberSpreadDataDTO res = memberService.getMemberSpreadData(getId(request));
        return ApiResult.success(res);

    }

    @ApiOperation("推广详情）")
    @GetMapping("/me/spread/list")
    public ApiResult<PageResult<MemberSpreadList>> memberSpreadList(HttpServletRequest request, int pageNo, int pageSize) {
        PageResult<MemberSpreadList> res = memberService.getMemberSpreadList(getId(request), pageNo, pageSize);
        return ApiResult.success(res);
    }

    @ApiOperation("发单派单检查）")
    @GetMapping("/member/action/check")
    public ApiResult<ActionDTO> actionCheck(HttpServletRequest request) {
        ActionDTO ret =  memberService.actionCheck(getId(request));
        return ApiResult.success(ret);
    }



}
